package jsoncache

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/fs"
	"os"
	"path/filepath"
	"reflect"
	"strings"
	"sync"
)

// 定义接口
type Cache interface {
	LoadDir(dir string) error
	reLoadDir(dir string) error
	Get(id uint64, target interface{}) error
	GetAll(targetSlice interface{}) error
}

type JsonCache struct {
	data map[string]map[uint64]string // 文件名 -> ID -> JSON字符串
	mu   sync.RWMutex                 // 读写锁
}

// 全局变量
var (
	once        sync.Once
	instance    *JsonCache
	ErrNotFound error
)

// 获取单例实例
func GetInstance() *JsonCache {
	once.Do(func() {
		instance = &JsonCache{
			data: make(map[string]map[uint64]string),
		}
	})
	return instance
}

// 加载指定目录下的json配置
func (c *JsonCache) LoadDir(dir string) error {
	c.mu.Lock()
	defer c.mu.Unlock()

	// 避免重复加载
	if len(c.data) > 0 {
		return errors.New("数据已加载，请勿重复初始化")
	}

	return filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
		if err != nil || d.IsDir() || filepath.Ext(path) != ".json" {
			return nil
		}

		// 获取基础文件名
		filename := strings.TrimSuffix(filepath.Base(path), ".json")

		// 读取文件内容
		raw, err := os.ReadFile(path)
		if err != nil {
			return fmt.Errorf("文件读取失败: %w", err)
		}

		// 解析为JSON数组
		var items []map[string]interface{}
		if err := json.Unmarshal(raw, &items); err != nil {
			return fmt.Errorf("JSON解析失败: %w", err)
		}

		// 初始化文件存储
		c.data[filename] = make(map[uint64]string)

		// 处理每个对象
		for _, item := range items {
			// 提取ID字段
			idValue, ok := item["id"]
			if !ok {
				return fmt.Errorf("缺少id字段: %s", path)
			}
			// 判断id是数字
			id, ok := idValue.(float64)
			if !ok {
				return fmt.Errorf("无效的id值: %s", path)
			}
			uint64Id := uint64(id)
			// 检查ID冲突
			if _, exists := c.data[filename][uint64Id]; exists {
				return fmt.Errorf("ID冲突: %d in %s", uint64Id, path)
			}

			// 存储JSON字符串
			itemBytes, _ := json.Marshal(item)
			c.data[filename][uint64Id] = string(itemBytes)
		}

		return nil
	})
}

// 私有方法,通过结构踢获取结构体的名称
func (c *JsonCache) getTypeName(i interface{}) string {
	// 使用 reflect.TypeOf() 获取 interface 的 Type
	t := reflect.TypeOf(i)
	// 如果 t 是一个指针，获取指针指向的类型
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	// 获取结构体的名称
	name := t.Name()
	fmt.Println("Type name:", name)
	return name
}

// 通过id获取单条数据
func (c *JsonCache) Get(id uint64, target interface{}) error {
	c.mu.RLock()
	defer c.mu.RUnlock()
	filename := c.getTypeName(target)
	fileData, exists := c.data[filename]
	if !exists {
		return fmt.Errorf("%w: 文件 %s", ErrNotFound, filename)
	}

	jsonStr, exists := fileData[id]
	if !exists {
		return fmt.Errorf("%w: ID %d", ErrNotFound, id)
	}

	return json.Unmarshal([]byte(jsonStr), target)
}

// 通过文件名称获取所有的数据
func (c *JsonCache) GetAll(target interface{}, targetSlice interface{}) error {
	c.mu.RLock()
	defer c.mu.RUnlock()
	// 获取
	filename := c.getTypeName(target)
	fileData, exists := c.data[filename]
	if !exists {
		return fmt.Errorf("%w: 文件 %s", ErrNotFound, filename)
	}

	slicePtr := reflect.ValueOf(targetSlice)
	if slicePtr.Kind() != reflect.Ptr || slicePtr.Elem().Kind() != reflect.Slice {
		return errors.New("目标必须是指向切片的指针")
	}

	slice := slicePtr.Elem()
	elemType := slice.Type().Elem()

	for _, jsonStr := range fileData {
		elem := reflect.New(elemType).Interface()
		if err := json.Unmarshal([]byte(jsonStr), elem); err != nil {
			return err
		}
		slice.Set(reflect.Append(slice, reflect.ValueOf(elem).Elem()))
	}

	return nil
}
